from PySide6.QtWidgets import QWidget, QVBoxLayout, QTabWidget, QLabel, QGridLayout
from PySide6.QtCore import Qt, QThread, Signal, QEvent, QTimer, QUrl, QObject, Slot
from PySide6.QtWebEngineWidgets import QWebEngineView
from PySide6.QtWebChannel import QWebChannel
from PySide6.QtGui import QColor, QClipboard
from PySide6.QtWidgets import QApplication
from datetime import datetime
import os
from logger.manager import LogManager
from .connection.serial_thread import SerialThread
from .connection.ssh_thread import SSHThread
from .connection.telnet_thread import TelnetThread

class TerminalBridge(QObject):
    def __init__(self, terminal):
        super().__init__()
        self.terminal = terminal
        self.buffer = []
        self.buffer_size = 1024  # 缓冲区大小
        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.flush_buffer)
        self.update_timer.start(16)  # 约60fps的刷新率

    dataReceived = Signal(str)
    cursorPositionChanged = Signal(int, int)
    
    @Slot(str)
    def copyToClipboard(self, text):
        """将文本复制到系统剪贴板"""
        if text:
            clipboard = QApplication.clipboard()
            clipboard.setText(text)
            self.logToFile('文本已复制到剪贴板')
    
    @Slot(result=str)
    def pasteFromClipboard(self):
        """从系统剪贴板获取文本"""
        try:
            clipboard = QApplication.clipboard()
            if clipboard:
                text = clipboard.text()
                if text is not None:
                    self.logToFile('从剪贴板获取文本')
                    return text
            self.logToFile('剪贴板为空或无法访问')
            return ""
        except Exception as e:
            self.logToFile(f'获取剪贴板内容失败: {str(e)}')
            return ""
    
    @Slot(str)
    def logToFile(self, message):
        """记录JavaScript端的日志信息"""
        if self.terminal and self.terminal.app_log:
            self.terminal.log_manager.write_log(self.terminal.app_log, message, "Terminal")
    
    def flush_buffer(self):
        if self.buffer:
            data = ''.join(self.buffer)
            self.dataReceived.emit(data)
            self.buffer.clear()
    
    @Slot(str)
    def sendData(self, data):
        if self.terminal.connection_thread and self.terminal.connection_thread.is_connected():
            self.terminal.connection_thread.write(data)
            
    @Slot(int, int)
    def updateCursorPosition(self, row, col):
        self.cursorPositionChanged.emit(row, col)

    @Slot(str)
    def logCommand(self, command):
        """记录用户输入的命令到操作日志"""
        timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S') # 获取当前时间戳
        if self.terminal.log_file:
            self.terminal.log_manager.write_log(self.terminal.log_file, f"[{timestamp}] {command} \n")

    def handle_received_data_by_buffer(self, data):
        """处理接收到的数据，使用缓冲机制"""
        self.buffer.append(data)
        if len(''.join(self.buffer)) >= self.buffer_size:
            self.flush_buffer()

    @Slot(result=str)
    def loadTerminalConfig(self):
        print("loadTerminalConfig")
        """从terminal.json文件中加载终端配置"""
        try:
            config_dir = os.path.expanduser('~/.a-terminal/settings')
            config_path = os.path.join(config_dir, 'terminal.json')
            if os.path.exists(config_path):
                with open(config_path, 'r', encoding='utf-8') as f:
                    config = f.read()
                return config
            else:
                # 如果用户目录下没有配置文件，尝试从项目目录加载（兼容旧版本）
                old_config_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'settings', 'terminal.json')
                if os.path.exists(old_config_path):
                    with open(old_config_path, 'r', encoding='utf-8') as f:
                        config = f.read()
                    return config
        except Exception as e:
            self.terminal.log_manager.write_log(self.terminal.app_log, f"加载终端配置失败: {str(e)}", "Terminal")
        # 返回默认配置
        return '{"fontSize":14,"theme":{"background":"#FFFFFF","foreground":"#000","cursor":"#000000","cursorAccent":"#000000","selectionBackground":"#3297FD","selectionForeground":"#FFFFFF"},"cursorStyle":"block"}'

class Terminal(QWidget):
    connection_status_changed = Signal(str, dict, bool)
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.connection_thread = None
        self.log_manager = LogManager()
        self.log_file = None
        self.session_log_file = None
        self.app_log = self.log_manager.get_log_file_path('app')
        self.cursor_row = 1
        self.cursor_col = 1
        self.setup_ui()

    def setup_ui(self):
        """初始化终端UI"""
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # 创建WebEngineView
        self.web_view = QWebEngineView()
        self.web_view.setContextMenuPolicy(Qt.NoContextMenu)
        
        # 创建WebChannel和Bridge对象
        self.channel = QWebChannel()
        self.bridge = TerminalBridge(self)
        self.channel.registerObject('terminal', self.bridge)
        self.web_view.page().setWebChannel(self.channel)
        
        # 连接光标位置变化信号
        self.bridge.cursorPositionChanged.connect(self.update_cursor_position)
        
        # 加载终端HTML页面
        html_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'templates', 'terminal.html')
        self.web_view.setUrl(QUrl.fromLocalFile(html_path))
        
        # 安装事件过滤器
        self.web_view.installEventFilter(self)

        # 设置WebEngineView的属性
        self.web_view.page().setBackgroundColor(QColor("transparent"))
        
        # 将WebEngineView添加到布局
        layout.addWidget(self.web_view)
        
    def connect_serial(self, port, baudRate, session_name=None):
        """连接Serial"""
        if not port or port == "无可用串口":
            error_msg = "无可用串口设备"
            self.handle_error(error_msg)
            self.log_manager.write_log(self.app_log, f"连接失败: {error_msg}", "Terminal")
            return
            
        if self.connection_thread and self.connection_thread.isRunning():
            self.disconnect()
            
        try:
            self.log_manager.write_log(self.app_log, f"尝试连接串口 {port}, 波特率: {baudRate}", "Terminal")
            self.bridge.handle_received_data_by_buffer(f'\r\n正在连接到 {port}, 波特率: {baudRate}...\r\n')
            self.connection_thread = SerialThread(port, baudRate)
            # 确保信号连接使用正确的参数类型
            self.connection_thread.received.connect(self.handle_received_data)
            self.connection_thread.error.connect(self.handle_error)
            self.connection_thread.connected.connect(self.update_ui_state)
            self.connection_thread.start()
            self.log_manager.write_log(self.app_log, f"串口连接线程已启动", "Terminal")
            
            # 创建新的日志文件，使用会话名称和时间戳
            if session_name and self.log_manager.is_logging_enabled():
                self.setup_session_log(session_name, f"串口会话 - 端口: {port}, 波特率: {baudRate}")
        except Exception as e:
            error_msg = f"连接失败: {str(e)}"
            self.handle_error(error_msg)
            self.log_manager.write_log(self.app_log, error_msg, "Terminal")
            self.update_ui_state(False)

    def connect_ssh(self, host, port, username, password, session_name=None):
        """连接SSH"""
        if self.connection_thread:
            self.disconnect()

        try:
            self.log_manager.write_log(self.app_log, f"尝试连接SSH服务器 {host}:{port}, 用户名: {username}", "Terminal")
            self.bridge.handle_received_data_by_buffer(f'\r\n正在连接到 SSH {host}:{port}...\r\n')
            
            # 创建SSH线程对象
            self.connection_thread = SSHThread(host, port, username, password)
            
            # 连接信号
            self.connection_thread.received.connect(self.handle_received_data)
            self.connection_thread.error.connect(self.handle_error)
            self.connection_thread.connected.connect(self.update_ui_state)
            
            # 启动线程
            self.connection_thread.start()
            self.log_manager.write_log(self.app_log, f"SSH连接线程已启动", "Terminal")

            if session_name and self.log_manager.is_logging_enabled():
                self.setup_session_log(session_name, f"SSH会话 - 主机: {host}, 端口: {port}")
        except Exception as e:
            error_msg = f"连接失败: {str(e)}"
            self.handle_error(error_msg)
            self.log_manager.write_log(self.app_log, error_msg, "Terminal")
            self.update_ui_state(False)

    def connect_telnet(self, host, port, session_name=None):
        """连接telnet"""
        if self.connection_thread and self.connection_thread.isRunning():
            self.disconnect()

        try:
            self.log_manager.write_log(self.app_log, f"尝试连接Telnet服务器 {host}:{port}", "Terminal")
            self.bridge.handle_received_data_by_buffer(f'\r\n正在连接到 Telnet {host}:{port}...\r\n')
            self.connection_thread = TelnetThread(host, port)
            # 确保信号连接使用正确的参数类型
            self.connection_thread.received.connect(self.handle_received_data)
            self.connection_thread.error.connect(self.handle_error)
            self.connection_thread.connected.connect(self.update_ui_state)
            self.connection_thread.start()
            self.log_manager.write_log(self.app_log, f"Telnet连接线程已启动", "Terminal")

            if session_name and self.log_manager.is_logging_enabled():
                self.setup_session_log(session_name, f"Telnet会话 - 主机: {host}, 端口: {port}")
        except Exception as e:
            error_msg = f"连接失败: {str(e)}"
            self.handle_error(error_msg)
            self.log_manager.write_log(self.app_log, error_msg, "Terminal")
            self.update_ui_state(False)

    def update_cursor_position(self, row, col):
        """更新光标位置并更新状态栏"""
        self.cursor_row = row
        self.cursor_col = col
        status_bar = self.window().status_bar
        if status_bar:
            status_bar.update_cursor_position(row, col)
            
    def update_ui_state(self, connected):
        """更新连接状态"""
        status_msg = '连接已建立' if connected else '连接已断开'
        self.log_manager.write_log(self.app_log, status_msg, "Terminal")
        self.update_device_info()

    def update_device_info(self):
        """更新设备信息显示"""
        status_bar = self.window().status_bar
        if not status_bar:
            self.log_manager.write_log(self.app_log, "未找到status_bar组件", "Terminal")
            return
            
        if self.connection_thread and self.connection_thread.is_connected():
            self.log_manager.write_log(self.app_log, "连接状态：已连接", "Terminal")
            # 从当前组件开始向上查找，直到找到TabManager
            current_widget = self
            while current_widget:
                if hasattr(current_widget, 'session_data'):
                    session_data = current_widget.session_data
                    session_type = session_data['config']['session_type']
                    params = session_data['config']['session_params']
                    self.log_manager.write_log(self.app_log, f"找到会话数据：类型={session_type}, 参数={params}", "Terminal")
                    status_bar.update_status(session_type, params, True)
                    return
                current_widget = current_widget.parent()
                self.log_manager.write_log(self.app_log, f"向上查找父组件：{current_widget}", "Terminal")
        else:
            self.log_manager.write_log(self.app_log, "连接状态：未连接", "Terminal")
        
        # 如果未连接或获取会话数据失败，显示未连接状态
        self.log_manager.write_log(self.app_log, "未找到会话数据，显示未连接状态", "Terminal")
        status_bar.update_status(None, None, False)

    def __del__(self):
        try:
            self.disconnect()
        except:
            pass

    def disconnect(self):
        if self.connection_thread:
            if self.log_file:
                self.log_manager.write_log(self.session_log_file, "会话结束")
            self.log_manager.write_log(self.app_log, "断开连接", "Terminal")
            try:
                self.connection_thread.disconnect()
                self.connection_thread = None
                self.log_file = None
                self.update_ui_state(False)
            except:
                pass

    def handle_received_data(self, data):
        """处理接收到的数据"""
        if not data:
            return
            
        # 通过Bridge发送数据到xterm.js
        self.bridge.handle_received_data_by_buffer(data)
        
        # 记录日志
        self.log_manager.write_log(self.session_log_file, data)

    def handle_error(self, error_msg):
        # 通过Bridge发送错误信息到xterm.js
        self.bridge.handle_received_data_by_buffer(f'\r\n错误: {error_msg}\r\n')
        # 记录错误信息到会话日志
        if self.log_file:
            self.log_manager.write_log(self.session_log_file, error_msg)
        # 记录错误信息到应用日志
        self.log_manager.write_log(self.app_log, f"错误: {error_msg}", "Terminal")

    def reload_terminal(self):
        """重新加载终端界面"""
        try:
            # 重新加载终端HTML页面
            html_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'templates', 'terminal.html')
            self.web_view.setUrl(QUrl.fromLocalFile(html_path))
            self.log_manager.write_log(self.app_log, "终端界面已重新加载", "Terminal")
        except Exception as e:
            self.log_manager.write_log(self.app_log, f"重新加载终端界面失败: {str(e)}", "Terminal")

    def setup_session_log(self, session_name, description):
        """创建并初始化会话日志文件"""
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')

        # 创建会话日志文件
        session_log_name = f"{session_name}_{timestamp}"
        self.session_log_file = self.log_manager.get_log_file_path(session_log_name)
        self.log_manager.write_log(self.session_log_file, f"会话开始: {description}-{timestamp} \n")
        
        self.log_manager.write_log(self.app_log, f"创建会话日志: {session_log_name}", "Terminal")